/***************************************************************
*  Copyright (c) 2007 by GroupMe! Team (www.groupme.net)
*  All rights reserved.
*
*  This file is part of the GroupMe! Project. Source code of 
*  this project is closed and redistribution of this code is
*  prohibited. 
*  
*  Contact: http://www.groupme.net
*
*  This copyright notice MUST APPEAR in all copies of the file!
***************************************************************/
package net.groupme.utils;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import de.nava.informa.core.ChannelIF;
import de.nava.informa.core.ParseException;
import de.nava.informa.impl.basic.ChannelBuilder;
import de.nava.informa.parsers.FeedParser;

import net.groupme.api.API_CONSTANTS;
import net.groupme.controller.model.ImageSearchResult;
import net.groupme.controller.model.LocationSearchResult;
import net.groupme.controller.model.SearchResult;
import net.groupme.gui.constants.VIEW_VOCABULARY;
import net.groupme.model.MODEL_CONSTANTS;

/**
 * created on Jun 12, 2008
 * 
 * This class provides HTTP utility methods.
 * 
 * @author Fabian Abel, <a href="mailto:abel@l3s.de">abel@l3s.de</a>
 * @author last edited by: $Author: fabian $
 * 
 * @version $Revision: 1.4 $ $Date: 2009-03-24 11:10:50 $
 */
public class HTTPUtilities {

	/*
	 * Parts of browser IDs...
	 */
	public static final String BROWSER_MOZILLA = "Mozilla";
	public static final String BROWSER_INTERNET_EXPLORER = "MSIE";
	public static final String BROWSER_OPERA = "Opera";
	
	/*
	 * Mime types 
	 */
	public static final String MIME_APP_RDF_XML = "application/rdf+xml";
	
	public static final String MIME_APP_XML = "application/xml";
	public static final String MIME_APP_XHTML_XML = "application/xhtml+xml";
	public static final String MIME_TEXT_XML = "text/xml";
	public static final String MIME_TEXT_HTML = "text/html";
	
	/**
	 * Mime types that may be preferable in comparison to rdf+xml 
	 */
	private static List<String> HTML_MIMETYPES_TO_CHECK = new ArrayList<String>();
	static {
		HTML_MIMETYPES_TO_CHECK.add(MIME_APP_XML);
		HTML_MIMETYPES_TO_CHECK.add(MIME_APP_XHTML_XML);
		HTML_MIMETYPES_TO_CHECK.add(MIME_TEXT_XML);
		HTML_MIMETYPES_TO_CHECK.add(MIME_TEXT_HTML);
	}
	
	/**
	 * This method analyzes the Accept parameter of the HTTP header and checks if 
	 * application/rdf+xml is one of the mime types that is preferred at most. If yes then
	 * we want to return RDF/XML to the client (even if e.g. text/html is preferred in the same
	 * way).  
	 * @param request the HTTP request
	 */
	@SuppressWarnings("unchecked")
	public static final String detectRequestedOutputFormat(HttpServletRequest request){
		//If user does only want to accept application/rdf+xml then deliver RDF/XML
		Enumeration values = request.getHeaders("accept");
		String accept = null;
		while (values.hasMoreElements()) {
			if(accept == null){
				accept = (String) values.nextElement();
			}else{
				accept += "," + (String) values.nextElement();
			}
		}
		if(accept == null){//standard output is HTML:
			return API_CONSTANTS.OUTPUT_HTML;
		}
		//mapping between quality values and accept identifiers
		Map<String, Double> acceptMap = new HashMap<String, Double>();
		//text/html, html/xml, application/rdf+xml;q=0.9, text/rdf+n3;q=0.9, application/turtle;q=0.9, application/rdf+n3;q=0.9, */*;q=0.8
		String mimeAndQuality = null;
		while(accept.contains(",")){
			mimeAndQuality = accept.substring(0, accept.indexOf(","));
			if(mimeAndQuality.contains(";q=")){
				acceptMap.put(mimeAndQuality.substring(0, mimeAndQuality.indexOf(";")), Double.parseDouble(mimeAndQuality.substring(mimeAndQuality.indexOf("=") + 1)));
			}else{
				acceptMap.put(mimeAndQuality, 1.0);
			}
			accept = accept.substring(accept.indexOf(",") + 1);
		}
		mimeAndQuality = accept;
		if(mimeAndQuality.contains(";q=")){
			acceptMap.put(mimeAndQuality.substring(0, mimeAndQuality.indexOf(";")), Double.parseDouble(mimeAndQuality.substring(mimeAndQuality.indexOf("=") + 1)));
		}else{
			acceptMap.put(mimeAndQuality, 1.0);
		}
		if(!acceptMap.containsKey(MIME_APP_RDF_XML)){
			return API_CONSTANTS.OUTPUT_HTML;
		}else if(acceptMap.get(MIME_APP_RDF_XML) == 1.0){
			return API_CONSTANTS.OUTPUT_RDF;
		}else{//compare quality/preference values
			for(String mime: HTML_MIMETYPES_TO_CHECK){
				if(acceptMap.containsKey(mime) && acceptMap.get(mime) > acceptMap.get(MIME_APP_RDF_XML)){
					return API_CONSTANTS.OUTPUT_HTML;
				}
			}
			return API_CONSTANTS.OUTPUT_RDF;
		}
	}
	
	public static void main(String[] args) {
		String accept = "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5";
		//mapping between quality values and accept identifiers
		Map<String, Double> acceptMap = new HashMap<String, Double>();
		//text/html, html/xml, application/rdf+xml;q=0.9, text/rdf+n3;q=0.9, application/turtle;q=0.9, application/rdf+n3;q=0.9, */*;q=0.8
		String mimeAndQuality = null;
		while(accept.contains(",")){
			mimeAndQuality = accept.substring(0, accept.indexOf(","));
			if(mimeAndQuality.contains(";q=")){
				acceptMap.put(mimeAndQuality.substring(0, mimeAndQuality.indexOf(";")), Double.parseDouble(mimeAndQuality.substring(mimeAndQuality.indexOf("=") + 1)));
			}else{
				acceptMap.put(mimeAndQuality, 1.0);
			}
			accept = accept.substring(accept.indexOf(",") + 1);
		}
		mimeAndQuality = accept;
		if(mimeAndQuality.contains(";q=")){
			acceptMap.put(mimeAndQuality.substring(0, mimeAndQuality.indexOf(";")), Double.parseDouble(mimeAndQuality.substring(mimeAndQuality.indexOf("=") + 1)));
		}else{
			acceptMap.put(mimeAndQuality.substring(0, mimeAndQuality.indexOf(";")), 1.0);
		}
		
		try {
			URL rssURL = new URL("http://groupme.org/GroupMe/group/1452?output=rdf");
			String contentType = rssURL.openConnection().getContentType();
			System.out.println(contentType);
			if(contentType.startsWith("text/xml") || contentType.startsWith("application/atom+xml")
					|| contentType.startsWith("application/rdf+xml")){
			ChannelIF channel = null;
			
			try {
				channel = FeedParser.parse(new ChannelBuilder(), rssURL);
			} catch (Exception e) {
			} 
			System.out.println(channel.getGenerator());
			}
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}
	
	 /**
     * Very small helper function to extract a given parameter or attribute from a HttpServletRequest.
     * @param request the {@link HttpServletRequest} object
     * @param parameter the parameter
     * @return the value of the parameter as a String
     */
    public static String getStringValue(HttpServletRequest request, String parameter){
    	String value = request.getParameter(parameter);
    	if(value == null && request.getAttribute(parameter) != null){ //normally this is not accessed but we do our best to extract the value.. 
    		value = request.getAttribute(parameter).toString();
    	}
    	return value;
    }
    
    /**
     * Returns the content type of the given URL, which will either be:
     * <ul>
     *   <li>{@link MODEL_CONSTANTS#RESOURCE_TYPE_AUDIO} </li>
     *   <li>{@link MODEL_CONSTANTS#RESOURCE_TYPE_IMAGE} </li>
     *   <li>{@link MODEL_CONSTANTS#RESOURCE_TYPE_VIDEO} </li>
     *   <li>{@link MODEL_CONSTANTS#RESOURCE_TYPE_SHOCKWAVE} </li>
     *   <li>{@link MODEL_CONSTANTS#RESOURCE_TYPE_RSS} </li>
     *   <li>{@link MODEL_CONSTANTS#RESOURCE_TYPE_GROUP} </li>
     *   <li>{@link MODEL_CONSTANTS#RESOURCE_TYPE_GROUPME_RESOURCE} </li>
     *   <li>{@link MODEL_CONSTANTS#RESOURCE_TYPE_WEBSITE} </li>
     * </ul>
     * @param url the URL of the resource
     * @return the GroupMe! content type of the given URL
     */
    public static String detectContentType(URL url){
		//special YouTube protocol
		if (url.toString().startsWith("http://www.youtube.com/watch?v=")
				|| url.toString().startsWith("http://youtube.com/watch?v=")){
			try {
				String vidId = url.toString().substring(url.toString().indexOf("v=")+2);
				if(vidId.indexOf("&") != -1){
					vidId = vidId.substring(0, vidId.indexOf("&"));
				}
				
				url = new URL("http://www.youtube.com/v/" + vidId);
			} catch (MalformedURLException e) {
				e.printStackTrace();
			}
		}
		//check whether the resource is a GroupMe! group:
		if (url.toString().startsWith(VIEW_VOCABULARY.RESTful_GROUP_URI_PATTERN)){
			return MODEL_CONSTANTS.RESOURCE_TYPE_GROUP;
		}
		//detect Type of content
		String contentType = "";
		try {
			contentType = url.openConnection().getContentType();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		//image
		if (contentType != null && contentType.startsWith("image")){
			return MODEL_CONSTANTS.RESOURCE_TYPE_IMAGE;
		}
		//video
		else if (contentType != null && contentType.startsWith("video")){
			return MODEL_CONSTANTS.RESOURCE_TYPE_VIDEO;
		}
		//audio
		else if (contentType != null && contentType.startsWith("audio")){
			return MODEL_CONSTANTS.RESOURCE_TYPE_AUDIO;
		}
		//application
		else if (contentType != null && "application/x-shockwave-flash".equals(contentType)){
			return MODEL_CONSTANTS.RESOURCE_TYPE_SHOCKWAVE;
		}
		//rss/atom?
		else if(contentType.startsWith("text/xml") || contentType.startsWith("application/atom+xml")
				|| contentType.startsWith("application/rdf+xml")){
			ChannelIF channel = null;
		
			try {
				channel = FeedParser.parse(new ChannelBuilder(), url);
			} catch (Exception e) {
				return MODEL_CONSTANTS.RESOURCE_TYPE_WEBSITE;
			}
			if(channel != null){
				return MODEL_CONSTANTS.RESOURCE_TYPE_RSS;
			}else{
				return MODEL_CONSTANTS.RESOURCE_TYPE_WEBSITE;
			}
		} 
		//other
		else {
			return MODEL_CONSTANTS.RESOURCE_TYPE_WEBSITE;
		}
    }   
    
    /**
     * HACK method to prepare special URLs (e.g. youtube Web sites -> Youtube Shackwave)
     * @param url the URL of the resource
     * @return the modified URL of the resource 
     */
    public static URL prepareSpecialURLs(URL url){
		//special YouTube protocol
		if (url.toString().startsWith("http://www.youtube.com/watch?v=")
				|| url.toString().startsWith("http://youtube.com/watch?v=")){
			try {
				String vidId = url.toString().substring(url.toString().indexOf("v=")+2);
				if(vidId.indexOf("&") != -1){
					vidId = vidId.substring(0, vidId.indexOf("&"));
				}
				
				url = new URL("http://www.youtube.com/v/" + vidId);
			} catch (MalformedURLException e) {
				e.printStackTrace();
			}
		}
		return url;
    }
}
